package gbench.appdemo.trading.proxy;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static gbench.common.tree.LittleTree.IRecord.*;
import gbench.common.tree.LittleTree.IRecord;
import gbench.appdemo.trading.agent.Agent;
import gbench.appdemo.trading.position.TradingPositionBill;
import gbench.appdemo.trading.position.TradeItem;
import gbench.commonApp.data.DataMatrixApp;


/**
 * 
 * @author gbench
 *
 */
public class ServiceProxy extends DataMatrixApp{
    
    private ServiceProxy() {}
    
    private static ServiceProxy proxy;
    public static ServiceProxy getInstance() {
        return proxy == null? proxy=new ServiceProxy():proxy;
    }
    
    /**
     * 
     * @param agentName
     * @param cons
     * @return
     */
    public ServiceProxy addAgent(String agentName,Consumer<Agent> cons) {
        var _agent = this.agents.computeIfAbsent(agentName,_name->{
            final var agent = new Agent(_name);
            return agent;
        });
        cons.accept(_agent);
        return this;
    }
    
    public ServiceProxy addProduct(String productName,Consumer<TradeItem> cons) {
        var pct = this.products.computeIfAbsent(productName,_name->{
            var product =  new TradeItem(_name);
            return product;
        });
        cons.accept(pct);
        return this;
    }
    
    public Agent randAgent(){
        return randIt(this.agents.entrySet().stream().map(e->e.getValue()).collect(Collectors.toList()));
    }
    
    public TradeItem randProduct(){
        return randIt(this.products.entrySet().stream().map(e->e.getValue()).collect(Collectors.toList()));
    }
    
    public static <T> T randIt(List<T> tt){
        if(tt==null||tt.size()<1)return null;
        var ir = new Random();
        return tt.get(ir.nextInt(tt.size()));
    }
    
    /**
     * 发布一个交易头寸
     * @param position
     */
    public void publishTradingPositionBill(TradingPositionBill position) {
        tradingPositionBills.add(position);
    }
    
    /**
     * 交易头寸
     * @return
     */
    public List<TradingPositionBill> getTradingPositionBills(Predicate<TradingPositionBill> predicate){
        return this.tradingPositionBills
            .parallelStream().filter(predicate)
            .collect(Collectors.toList());
    }
    
    /**
     * 交易头寸
     * @return
     */
    public List<TradingPositionBill> getTradingPositionBills(Agent agent){
        return getTradingPositionBills(e->e.getOwner().equals(agent));
    }
    
    /**
     * 试算平衡
     * 
     * @param positions
     * @param unitPrice 拟定的成交价格
     * @param drcr 撮合方式 
     */
    public void trialBalance(final Predicate<TradingPositionBill> filter) {
        this.trialBalance(this.getTradingPositionBills(e->true),filter);
    }
    
    /**
     * 试算平衡
     * 
     * @param positions
     * @param filter 拟定的成交价格 
     */
    public void trialBalance(final List<TradingPositionBill> positions,final Predicate<TradingPositionBill> filter) {
       final var rr =  positions.stream()
            .filter(filter)
            .map(e->REC(
                "id",e.getId(),
                "owner",e.getOwner().getName(),
                "product",e.getUnderlying().getName(),
                "position",e.getPosition(),
                "quantity",e.getQuantity(),
                "unitPrice",e.getUnitPrice(),
                "createTime",e.getCreateTime()
            )); // 满足多单匹配的价格。
        
       final var rec = IRecord.pivotTable(rr, "product,position".split(","),e->e.stream()
        .sorted((a,b)->a.ldt("createTime").compareTo(b.ldt("createTime"))).collect(llclc(p->p)));
       //
       rec.foreach((String product,IRecord p)->{
           System.out.println(product);
           p.foreach((pos,o)->{
               System.out.println(pos+"-->"+o);
           });
       });
    }
    
    
    public List<Agent> getAgents() {
        return agents.entrySet().stream().map(e->e.getValue()).collect(Collectors.toList());
    }
    
    public Agent getAgent(String name) {
        return agents.get(name);
    }

    public Map<String, TradeItem> getTradeItems() {
        return products;
    }

    public List<TradingPositionBill> getTradingPositionBills() {
        return tradingPositionBills;
    }

    final Map<String,Agent> agents = new HashMap<String,Agent>();
    final Map<String,TradeItem> products = new HashMap<String,TradeItem>();
    final List<TradingPositionBill> tradingPositionBills = new LinkedList<TradingPositionBill>();
}
